﻿using UnityEngine;
using System.Collections;

public class enemyScript : MonoBehaviour {

	public int weaponDamage =1;
	public float bulletSpeed = 5.2f;
	public GameObject bullet;
	private Transform player;
	public int health;
    private int startingHealth;
	private int damage;
    public int xp;
	public bool isAttacking;
	public bool helpCalled;
	public GameObject parent;
	public GameObject holderGO;
	public GameObject bloodSpray;
	public GameObject bloodSplat;
	public GameObject muzzleFlash;
    public GameObject fov;
    public GameObject visionCollider;
	private Rigidbody2D rbod;
	public float speed;
	private float idleRotate;
	public bool rotateCW;
	private float rotateSpeed = 0.5f;
	private bool rotateReset = true;
	private bool isWaiting;
	public bool canShoot;
	private float waitTime = 0.0f;
	public int accuracy;
	public float reloadSpeed;
	public float reloadTime;
	public float weaponAccuracy;
	public float attackRange;
	public float accuracyDivider;
	public int clipSize;
	public int ammoRemaining;
	private bool isReloading;
    private float shotCooldown;
    private float alertTime = 1.5f;
    public bool isAlert;
    public float fireRate;
    public bool isDead;
    private Vector2 startPos;
    private Quaternion startRot;
    public Sprite deadSprite;
    public Sprite aliveSprite;

	// Use this for initialization
	void Start(){
        startingHealth = health;
		attackRange = 8.0f;
		ammoRemaining = clipSize;
		idleRotate = 0.0f;
		player = GameObject.FindGameObjectWithTag ("Player").transform;		
		rbod = holderGO.GetComponent<Rigidbody2D> ();
        startPos = rbod.position;
        startRot = parent.transform.rotation;
        //set accuracy divider based on accuracy level of game object
        switch (accuracy) {
		case 1:
			accuracyDivider = 1f;
			break;
		case 2:
			accuracyDivider = 1.25f;
			break;
		case 3:
			accuracyDivider = 1.5f;
			break;
		case 4:
			accuracyDivider = 1.75f;
			break;
		case 5:
			accuracyDivider = 2f;
			break;
		default:
			accuracyDivider = 1f;
			break;
		}
    }

	void FixedUpdate(){
        //move towards player if attacking
        if (isAttacking && !isDead)
        {
            Vector2 playerPostion = player.position;
            playerPostion.x = playerPostion.x - transform.position.x;
            playerPostion.y = playerPostion.y - transform.position.y;
            Vector2 move = new Vector2(0, 0);
            if (playerPostion.x < 0)
            {
                move.x = -1;
            }
            if (playerPostion.x > 0)
            {
                move.x = 1;
            }
            if (playerPostion.y < 0)
            {
                move.y = -1;
            }
            if (playerPostion.y > 0)
            {
                move.y = 1;
            }
            float distance = Vector2.Distance(transform.position, player.position);
            speed = distance * 0.2f;
            if (speed < 0.4f) { speed = 0.4f; }
            if (speed > 2f) { speed = 2f; }
            rbod.MovePosition(rbod.position + move * speed * Time.deltaTime);
        }
	}
	// Update is called once per frame
	void Update () {
        //check if alive
        if (!isDead)
        {
            //check alertness
            if (isAlert)
            {
                if (alertTime <= 0)
                {
                    isAttacking = true;
                    isAlert = false;
                }
                alertTime -= Time.deltaTime;
            }
            else { alertTime = 1.5f; }

            //reload if out of ammo
            if (isReloading)
            {
                if (reloadTime <= 0)
                {
                    ammoRemaining = clipSize;
                    isReloading = false;
                }
                reloadTime -= Time.deltaTime;
            }

            //idle
            if (!isAttacking)
            {
                idle();
            }
            //look at the player if player has triggered attack
            if (isAttacking)
            {
                Vector2 playerPostion = player.position;
                playerPostion.x = playerPostion.x - transform.position.x;
                playerPostion.y = playerPostion.y - transform.position.y;
                float angle = Mathf.Atan2(playerPostion.y, playerPostion.x) * Mathf.Rad2Deg;
                Quaternion rot = Quaternion.Euler(0, 0, angle);
                parent.transform.rotation = rot;
            }
            //activate other nearby enemies when this enemy starts attacking
            if (isAttacking && !helpCalled)
            {
                var calledEnemies = GameObject.FindGameObjectsWithTag("enemy");
                Vector2 myPos = new Vector2(transform.position.x, transform.position.y);
                //check the array has something in it
                if (calledEnemies != null && calledEnemies.Length > 0)
                {
                    for (int i = 1; i <= calledEnemies.Length; i++)
                    {
                        //get position of enemy and calculate distance
                        Vector2 target = new Vector2(calledEnemies[i - 1].transform.position.x, calledEnemies[i - 1].transform.position.y);
                        float distance = Vector2.Distance(myPos, target);
                        //if the enemy called is close enough, have them attack too
                        if (distance < 7.0f)
                        {
                            calledEnemies[i - 1].GetComponent<enemyScript>().isAttacking = true;
                        }
                    }
                }
                //set to true so help is only called once
                helpCalled = true;
            }
            //check if enemy is attacking and call the shoot function
            if (isAttacking)
            { shoot(); }
        }
	}

	void shoot() {
		//fire at the player if not currently reloading and player is in sight
		if (canShoot && !isReloading) {
            if (shotCooldown < 0)
            {
                //get random accurcay jitter
                float randAccX = Random.Range(-weaponAccuracy, weaponAccuracy);
                float randAccY = Random.Range(-weaponAccuracy, weaponAccuracy);
                Vector2 accuracyJitter = new Vector2(randAccX / accuracyDivider, randAccY / accuracyDivider);
                //collect postions of target and gameObject
                Vector2 playerPosition = player.position;
                Vector2 myPos = transform.position;
                float distance = Vector2.Distance(myPos, playerPosition);
                //caculate direction and add jitter
                Vector2 direction = (playerPosition - myPos) + accuracyJitter;
                playerPosition.x = playerPosition.x - transform.position.x;
                playerPosition.y = playerPosition.y - transform.position.y;
                float angle = Mathf.Atan2(playerPosition.y, playerPosition.x) * Mathf.Rad2Deg;
                Quaternion rot = Quaternion.Euler(0, 0, angle);
                //only shoot if close enough to player
                if (distance <= attackRange)
                {
					muzzleFlash.GetComponent<muzzleFlashScript> ().shotFired = true;
					GameObject projectile = (GameObject)Instantiate(bullet, myPos, rot);
                    //checks what weapon is equiped and sets bullets damage
                    projectile.GetComponent<enemyBulletBehavior>().damage = weaponDamage;
                    projectile.GetComponent<Rigidbody2D>().velocity = direction * bulletSpeed;
                    ammoRemaining--;
                    shotCooldown = fireRate;
                    if (ammoRemaining == 0)
                    {
                        isReloading = true;
                        reloadTime = reloadSpeed;
                    }
                }
            } else { shotCooldown -= Time.deltaTime; }
		} else { shotCooldown = 0; }
	}

	void idle(){
		float rand = Random.Range (0.8f, 2.5f);
		if (!isWaiting) {			
			Quaternion zFrom = parent.transform.rotation;
			Quaternion zTo	= Quaternion.Euler (0, 0, idleRotate);
			if (rotateCW) {
				parent.transform.rotation = Quaternion.Lerp (zFrom, zTo, 1);
				idleRotate -= rotateSpeed;
				if (parent.transform.rotation.eulerAngles.z > 178 && parent.transform.rotation.eulerAngles.z < 180 && rotateReset) {				
					rotateSpeed = rotateSpeed * -1;
					rotateReset = false;
					isWaiting = true;
					waitTime = rand;
				}
				if (parent.transform.rotation.eulerAngles.z > 358 && !rotateReset) {				
					rotateSpeed = rotateSpeed * -1;
					rotateReset = true;
					isWaiting = true;
					waitTime = rand;
				}
			} else {						
				parent.transform.rotation = Quaternion.Lerp (zFrom, zTo, 1);
				idleRotate += rotateSpeed;
				if (parent.transform.rotation.eulerAngles.z > 180 && rotateReset) {				
					rotateSpeed = rotateSpeed * -1;
					rotateReset = false;
					isWaiting = true;
					waitTime = rand;
				}
				if (parent.transform.rotation.eulerAngles.z < 2 && !rotateReset) {				
					rotateSpeed = rotateSpeed * -1;
					rotateReset = true;
					isWaiting = true;
					waitTime = rand;
				}
			}
		} else {
			if (waitTime <= 0) {
				isWaiting = false;
			}
			waitTime -= Time.deltaTime;
		}
	}
	//take damage when shot by the player
	void OnTriggerEnter2D(Collider2D col)
	{
		if (col.tag == "bullet" && !isDead) {
			//calculate a rotation based on bullet and create a blood spray effect in the reverse direction
			Vector2 bulletPosition = col.transform.position;
			bulletPosition.x = bulletPosition.x - transform.position.x;
			bulletPosition.y = bulletPosition.y - transform.position.y;
			float angle = Mathf.Atan2(bulletPosition.y, bulletPosition.x) * Mathf.Rad2Deg;	
			var rotationVector = transform.rotation.eulerAngles;
			rotationVector.x = angle * -1;
			rotationVector.y = 90;
			rotationVector.z = 0;
			GameObject.Instantiate (bloodSpray, transform.position, Quaternion.Euler(rotationVector));

			//add blood splat to ground
			GameObject.Instantiate (bloodSplat, transform.position, transform.rotation);

			damage = col.GetComponent<bulletBehavior> ().damage;
			health -= damage;
			isAttacking = true;
		}
	}

    public void resetObject()
    {
        //reset states back to default
        isAlert = false;
        isDead = false;
        isAttacking = false;

        //reset health
        health = startingHealth;

        //set transform back to its beginning location
        rbod.position = startPos;
        parent.transform.rotation = startRot;

        //set sprite back to normal
        gameObject.GetComponent<SpriteRenderer>().sprite = aliveSprite;

        //enable collider
        gameObject.GetComponent<BoxCollider2D>().enabled = true;

        //enable FOV
        fov.SetActive(true);
        fov.GetComponent<MeshRenderer>().material = visionCollider.GetComponent<visionScript>().normalMat;
        visionCollider.SetActive(true);
    }

    public void killObject()
    {
        //set states
        isDead = true;
        isAttacking = false;
        health = 0;

        //set sprite to dead
        gameObject.GetComponent<SpriteRenderer>().sprite = deadSprite;       

        //disable collider
        gameObject.GetComponent<BoxCollider2D>().enabled = false;

        //disable FOV
        fov.SetActive(false);
        visionCollider.SetActive(false);

    }
}
